<?php

namespace App\Http\Middleware\Api;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Closure;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;

class AdminRefreshTokenMiddleware extends BaseMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param \Illuminate\Http\Request $request
     * @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse)  $next
     * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
     */
    public function handle( Request $request, Closure $next )
    {
        config(['auth.defaults.guard' => 'admin']);

        // 检查此次请求中是否带有 token，如果没有则抛出异常。
        $this->checkForToken( $request );

        //1. 格式通过，验证是否是专属于这个的token

        //获取当前守护的名称
        $present_guard = Auth::getDefaultDriver();

        //获取当前token
        $token = Auth::getToken();

        //即使过期了，也能获取到token里的 载荷 信息。
        $payload = Auth::manager()->getJWTProvider()->decode( $token->get() );

        //如果不包含guard字段或者guard所对应的值与当前的guard守护值不相同
        //证明是不属于当前guard守护的token
        if ( empty( $payload['role'] ) || $payload['role'] != $present_guard ) {
            throw new TokenInvalidException();
        }
        //使用 try 包裹，以捕捉 token 过期所抛出的 TokenExpiredException  异常
        //2. 此时进入的都是属于当前guard守护的token
        try {
            /**
            // 检测用户的登录状态，如果正常则通过
            if ( $this->auth->parseToken()->authenticate() ) {
                return $next( $request );
            }
            throw new UnauthorizedHttpException( 'jwt-auth', '未登录' );
             */

            // 检测用户的登录状态，如果正常则通过 - 自定义
            if ( auth($payload['role'])->user() ) {
                return $next( $request );
            }
            throw new UnauthorizedHttpException( 'jwt-auth', '未登录' );
        } catch ( TokenExpiredException $exception ) {
            // 3. 此处捕获到了 token 过期所抛出的 TokenExpiredException 异常，我们在这里需要做的是刷新该用户的 token 并将它添加到响应头中
            try {
                // 刷新用户的 token
                //$token = $this->auth->refresh();
                $token = auth($payload['role'])->refresh();
                // 使用一次性登录以保证此次请求的成功
                //Auth::onceUsingId( $this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub'] );
                auth($payload['role'])->onceUsingId( $payload['sub'] );
            } catch ( JWTException $exception ) {
                // 如果捕获到此异常，即代表 refresh 也过期了，用户无法刷新令牌，需要重新登录。
                throw new UnauthorizedHttpException( 'jwt-auth', $exception->getMessage() );
            }
        }

        // 在响应头中返回新的 token
        return $this->setAuthenticationHeader( $next( $request ), $token );
    }
}
